package components;

import java.util.ArrayList;

import managers.FeatureManager;

import ontology.PartOfSpeech;

import org.jdom2.Element;

import features.Feature;

public class Phrase extends Component{

	private Children children;
	
	public Phrase(Element componentElement, boolean autoAddDefaultFeatures) {
		super(componentElement, autoAddDefaultFeatures);
		children = new Children(new ArrayList<Component>());
	}
	
	public Phrase(String componentName, boolean autoAddDefaultFeatures){
		super(componentName, autoAddDefaultFeatures);
		this.children = new Children(new ArrayList<Component>());
	}

	// new added nov.23
	public boolean matches(Component pattern){
		if(!this.getPOSCode().equals(pattern.getPOSCode()))
			return false;
		if(!featuresMatch(pattern))
			return false;
		
		for(Component patChild: pattern.getChildren().getChildren())
		{
			boolean match = false;
			for(Component inputChild: this.getChildren().getChildren()){
				if(inputChild.matches(patChild))
				{
					match = true;
					break;
				}
			}
			if(!match && !patChild.isOptional())
				return false;
		}
		return true;
	}
	
	public ArrayList<Component> getMatchedComponents(Component pattern){
		if(!this.getPOS().equals(pattern.getPOS()))
			return new ArrayList<Component>();
		if(!featuresMatch(pattern))
			return new ArrayList<Component>();
		
		
		ArrayList<Component> matchedComponents = new ArrayList<Component>();
		this.setTagNonRecursively(pattern.getTag());
		matchedComponents.add(this);
		
		for(Component patChild: pattern.getChildren().getChildren())
		{
			boolean match = false;
			for(Component inputChild: this.getChildren().getChildren()){
				if(inputChild.matches(patChild))
				{
					match = true;
					matchedComponents.addAll(inputChild.getMatchedComponents(patChild));
					break;
				}
			}
			if(!match && !patChild.isOptional())
				return new ArrayList<Component>();
		}
		
		
		return matchedComponents;
	}
	
	public void addChild(Component child){
		children.addChild(child);
		child.setParent(this);
	}

	public String getStringForPrinting() {
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.append(name+"(");
		for(Component child: children.getChildren())
			stringBuilder.append(child.toString());
		stringBuilder.append(")");
		return stringBuilder.toString();
	}
	
	protected String getFeatures(boolean includeDefaults, String nextLineToken){
		StringBuilder featureString = new StringBuilder();
		featureString.append("*****Features");
		if(!includeDefaults)
			featureString.append("(Non-default)");
		
		featureString.append("*****");
		featureString.append(nextLineToken);
		
		for(Feature feature: featureList.getFeatureList()){	
			if(includeDefaults || !FeatureManager.isFeatureDefault(name, feature.getName(), feature.getValue())){
				featureString.append(feature.getName()+" = "+feature.getValue());
				if(!feature.isStandard())
					featureString.append(" [Custom Feature]");
				featureString.append(nextLineToken);
			}
		}
		featureString.append(nextLineToken);
		return featureString.toString();
	}
	
	public boolean isLeaf() {
		return false;
	}

	public Children getChildren() {
		return children;
	}

	public String toString() {
		return name;
	}

	@Override
	public String toGeneratedString() {
		return toString();
	}
	
	@Override
	protected void addAdditionalXMLContent(Element parentElement, boolean isRuleMode) {
		if(isRuleMode)
			for(Component child: children.getChildren())	
				parentElement.addContent(child.generateXMLElementForRuleComponent());
		else
			for(Component child: children.getChildren())	
				parentElement.addContent(child.generateXMLElement());
	}

	@Override
	public String toLexiconSentence() {
		StringBuilder sb = new StringBuilder();
		int numChildren = children.getChildren().size();
		ArrayList<Component> childList = children.getChildren();
		
		for(int i=0; i < numChildren; i++){
			Component child = children.getChildren().get(i);
			String childSentence = child.toLexiconSentence();
			if(!childSentence.isEmpty()){
				sb.append(childSentence);
				if(i < numChildren - 1 && !childList.get(i+1).toLexiconSentence().equals("."))
					sb.append(" ");
			}
		}
		
		if(this.getPOSCode().equalsIgnoreCase(PartOfSpeech.CLAUSE)){
			sb.append(".");
			sb.replace(0, 1, ""+Character.toUpperCase(sb.charAt(0)));
		}
				
		return sb.toString();
	}
	
	@Override
	public String toConceptSentence() {
		StringBuilder sb = new StringBuilder();
		int numChildren = children.getChildren().size();
		ArrayList<Component> childList = children.getChildren();
		
		for(int i=0; i < numChildren; i++){
			Component child = children.getChildren().get(i);
			String childSentence = child.toConceptSentence();
			if(!childSentence.isEmpty()){
				sb.append(childSentence);
				if(i < numChildren - 1 && !childList.get(i+1).toConceptSentence().equals("."))
					sb.append(" ");
			}
		}
		return sb.toString();
	}

	public void insertChildAt(int index, Component child){
		children.addChild(index, child);
		child.setParent(this);
	}

	public void removeChild(Component child){
		children.removeChild(child);
		child.setParent(null);
	}
	
	public int setTag(int nextTag) {
		this.tag = nextTag;
		nextTag++;
		
		for(Component child: children.getChildren())
			nextTag = child.setTag(nextTag);
		
		return nextTag;
	}

	public void resetTag(){
		this.tag = -1;
		
		for(Component child: children.getChildren())
			child.resetTag();
	}
	
	
	public Component getComponentByTag(int tag) {
		if(this.tag == tag)
			return this;
		
		for(Component child: children.getChildren()){
			Component potentialMatch = child.getComponentByTag(tag);
			if(potentialMatch != null)
				return potentialMatch;
		}
		
		return null;
	}

	@Override
	public int getMaxTag() {
		int maxTag = -1;
		
		for(Component component: children.getChildren()){
			int currTag = component.getMaxTag();
			if(currTag > maxTag)
				maxTag = currTag;
		}
		
		return maxTag;
	}

}